package com.xz.diagnosisOrder.service.impl;

import com.xz.common.exception.ServiceException;
import com.xz.common.service.ISysAccessoryService;
import com.xz.common.utils.DateUtils;
import com.xz.common.utils.SecurityUtils;
import com.xz.common.utils.StringUtils;
import com.xz.diagnosisOrder.domain.DiagnosisOrder;
import com.xz.diagnosisOrder.domain.DiagnosisRefundOrder;
import com.xz.diagnosisOrder.domain.DiagnosisTreatmentOrder;
import com.xz.diagnosisOrder.dto.DiagnosisRefundOrderConfirmDto;
import com.xz.diagnosisOrder.enums.PaymentStatusEnum;
import com.xz.diagnosisOrder.service.IDiagnosisExpenseService;
import com.xz.diagnosisOrder.service.IDiagnosisOrderLogService;
import com.xz.expense.domain.ExpenseBill;
import com.xz.expense.enums.ExpenseBillBizTypeEnum;
import com.xz.expense.enums.ExpenseBillStatusEnum;
import com.xz.expense.mapper.ExpenseBillMapper;
import com.xz.member.domain.MemberInfo;
import com.xz.member.mapper.MemberInfoMapper;
import com.xz.member.service.IWalletRecordService;
import com.xz.message.service.ISysTenantNotifyItemService;
import com.xz.message.vo.MemberMsgInfo;
import com.xz.patient.domain.PatientInfo;
import com.xz.patient.mapper.PatientInfoMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;

/**
 * 诊疗（预约/挂号）单费用Service业务层处理
 *
 * @author xz
 * @date 2024-03-17
 */
@Service
public class DiagnosisExpenseServiceImpl implements IDiagnosisExpenseService {
  @Autowired
  private ExpenseBillMapper expenseBillMapper;
  @Resource
  private MemberInfoMapper memberInfoMapper;
  @Autowired
  private IWalletRecordService walletRecordService;
  @Autowired
  private ISysTenantNotifyItemService sysTenantNotifyItemService;
  @Resource
  private PatientInfoMapper patientInfoMapper;
  @Autowired
  private IDiagnosisOrderLogService diagnosisOrderLogService;
  @Autowired
  private ISysAccessoryService iSysAccessoryService;
  /**
   * 扣减会员的钱包余额(挂号单)
   * @param order
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void deductionOfAccountBalance(DiagnosisOrder order) {
    //未支付则直接返回
    if (!PaymentStatusEnum.PAID.eq(order.getPaymentStatus())) {
      return;
    }
    //插入费用账单数据
    insertExpenseBill(order, ExpenseBillBizTypeEnum.REGISTRATION_ORDER.getType(), ExpenseBillStatusEnum.CONFIRMED.getStatus());
    //扣钱包的钱
    BigDecimal walletPay = order.getWalletPay();
    if(null != walletPay && walletPay.compareTo(BigDecimal.ZERO) == 1){
      // 获取会员的余额
      MemberInfo memberInfo = memberInfoMapper.memberInfoByCardNo(order.getMemberCardNo());
      // 扣减会员的钱包余额
      deductionsAccountBalance(walletPay, memberInfo);
      // 新增钱包流水记录（8:挂号单消费 , 2:减钱）
      walletRecordService.addBizRecord(order.getMemberCardNo(), 8, 2, order.getOrderNo(), order.getWalletPay(), order.getDeptId());
      // 发送账户余额/积分余额短信
      sendMemberBalanceConsumptionMsg(memberInfo, walletPay, 1);
      //更新客户患者累计消费值
      updatePatientAccumulatedConsumption(order.getPatientId(), order.getCollectionAmount());
    }

    // 诊疗模块的报表日志
    diagnosisOrderLogService.insertByOrder(order,1,1);
  }

  /**
   * 扣减会员的钱包余额(诊疗单)
   * @param mainOrder
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void deductionOfAccountBalance(DiagnosisTreatmentOrder mainOrder) {
    //未支付则直接返回
    if (!PaymentStatusEnum.PAID.eq(mainOrder.getPaymentStatus())) {
      return;
    }
    //插入费用账单数据
    insertExpenseBill(mainOrder, ExpenseBillBizTypeEnum.TREATMENT_ORDER.getType(), ExpenseBillStatusEnum.CONFIRMED.getStatus());
    //扣钱包的钱
    BigDecimal walletPay = mainOrder.getWalletPay();
    if(null != walletPay && walletPay.compareTo(BigDecimal.ZERO) == 1){
      // 获取会员的余额
      MemberInfo memberInfo = memberInfoMapper.memberInfoByCardNo(mainOrder.getMemberCardNo());
      // 扣减会员的钱包余额
      deductionsAccountBalance(walletPay, memberInfo);
      // 新增钱包流水记录（6:诊疗单消费 , 2:减钱）
      walletRecordService.addBizRecord(memberInfo.getMemberCardNo(), 6, 2, mainOrder.getOrderNo(), walletPay, mainOrder.getDeptId());
      // 发送账户余额/积分余额短信
      sendMemberBalanceConsumptionMsg(memberInfo, walletPay, 1);
      //更新客户患者累计消费值
      updatePatientAccumulatedConsumption(mainOrder.getPatientId(), mainOrder.getCollectionAmount());
    }
  }

  /**
   * 扣减会员的钱包余额
   * @param walletPay
   * @param memberInfo
   */
  private void deductionsAccountBalance(BigDecimal walletPay, MemberInfo memberInfo) {
    if(null == memberInfo){
      throw new ServiceException("会员卡号不存在！");
    }
    BigDecimal memberBalance = memberInfo.getWalletBalance();
    // 支付的金额大于会员余额时，报金额不足
    if (walletPay.compareTo(memberBalance) == 1) {
      throw new ServiceException("钱包余额不足！");
    }
    // 扣减余额,并且更新钱包
    memberInfo.setWalletBalance(memberBalance.subtract(walletPay));
    // 更新会员钱包余额
    boolean flag = memberInfoMapper.updateById(memberInfo) > 0;
    if (!flag) {
      throw new ServiceException("钱包扣减余额失败。");
    }
  }

  /**
   * 退回会员的钱包余额
   * @param walletPay
   * @param memberNo
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void refundAccountBalance(BigDecimal walletPay, String memberNo) {

    if(StringUtils.isEmpty(memberNo)){
      throw new ServiceException("会员卡号不存在，无法退款！");
    }
    // 获取会员的余额
    MemberInfo memberInfo = memberInfoMapper.memberInfoByCardNo(memberNo);
    if(null == memberInfo){
      throw new ServiceException("会员卡号数据不存在，无法退款！");
    }

    BigDecimal memberBalance = memberInfo.getWalletBalance();
    // 扣减余额,并且更新钱包
    memberInfo.setWalletBalance(memberBalance.add(walletPay));
    // 更新会员钱包余额
    boolean flag = memberInfoMapper.updateById(memberInfo) > 0;
    if (!flag) {
      throw new ServiceException("钱包退还余额失败。");
    }
    // 发送账户余额/积分余额短信
    sendMemberBalanceConsumptionMsg(memberInfo, walletPay, 2);
  }

  /**
   * 挂号/诊疗余额变动（消费/退费）·短信发送
   * @param memberInfo       会员信息
   * @param variableAmount   钱包余额变动
   * @param variableIntegral 积分余额变动
   * @param msgType          消息类型（ 1会员钱包消费,2会员钱包消费退款）
   */
  private void sendMemberBalanceConsumptionMsg(MemberInfo memberInfo, BigDecimal variableAmount, Integer msgType) {
    // 发送账户余额/积分余额短信
    MemberMsgInfo msgInfo = new MemberMsgInfo();
    msgInfo.setId(memberInfo.getId());
    BeanUtils.copyProperties(memberInfo, msgInfo);
    msgInfo.setVariableAmount(variableAmount);
    msgInfo.setVariableIntegral(new BigDecimal("0"));
    sysTenantNotifyItemService.sendMemberInfoMsg(msgInfo, msgType, SecurityUtils.getLoginUser().getUser());
  }

  /**
   * 更新客户患者累计消费值
   * @param patientId 患者id
   * @param collectionAmount 追加的消费值
   */
  private void updatePatientAccumulatedConsumption(Long patientId, BigDecimal collectionAmount) {
    // 更新客户患者累计消费值
    PatientInfo patientInfo = patientInfoMapper.selectById(patientId);
    BigDecimal accumulatedConsumption = patientInfo.getAccumulatedConsumption();
    patientInfo.setAccumulatedConsumption(accumulatedConsumption.add(collectionAmount));
    boolean flag = patientInfoMapper.updateById(patientInfo) > 0;
    if (!flag) {
      throw new ServiceException("更新客户患者累计消费值失败！");
    }
  }

  /**
   * 插入费用账单数据
   * @param order 诊疗单
   * @param bizType 业务类型 ExpenseBillBizTypeEnum
   * @param status 状态 ExpenseBillStatusEnum
   * @return
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public  ExpenseBill insertExpenseBill(DiagnosisOrder order, Integer bizType, Integer status) {
    ExpenseBill expenseBill = new ExpenseBill();
    //填充基本单据信息
    expenseBill.setBizId(order.getId());
    expenseBill.setBizNo(order.getOrderNo());
    expenseBill.setBizType(bizType);// 挂号单
    expenseBill.setStatus(status);// 已确认
    //填充业务数据信息
    expenseBill.setPatientId(order.getPatientId());
    expenseBill.setReceivableCost(order.getRegistrationFee());
    expenseBill.setPreferentialCost(order.getPreferentialAmount());
    expenseBill.setActCost(order.getCollectionAmount());
    //创建人信息
    expenseBill.setDeptId(order.getDeptId());
    expenseBill.setTenantId(order.getTenantId());
    expenseBill.setCreateBy(order.getCreateBy());
    expenseBill.setCreateTime(DateUtils.getNowDate());
    //新增费用单
    expenseBillMapper.insertExpenseBill(expenseBill);
    return expenseBill;
  }

  /**
   * 插入费用账单数据
   * @param order 诊疗单
   * @param bizType 业务类型 ExpenseBillBizTypeEnum
   * @param status 状态 ExpenseBillStatusEnum
   * @return
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public   ExpenseBill insertExpenseBill(DiagnosisTreatmentOrder order, Integer bizType, Integer status) {
    ExpenseBill expenseBill = new ExpenseBill();
    //填充基本单据信息
    expenseBill.setBizId(order.getId());
    expenseBill.setBizNo(order.getOrderNo());
    expenseBill.setBizType(bizType);
    expenseBill.setStatus(status);
    //填充业务数据信息
    expenseBill.setPatientId(order.getPatientId());
    expenseBill.setReceivableCost(order.getTotalPrice());
    expenseBill.setPreferentialCost(order.getPreferentialAmount());
    expenseBill.setActCost(order.getCollectionAmount());
    //创建人信息
    expenseBill.setDeptId(order.getDeptId());
    expenseBill.setTenantId(order.getTenantId());
    expenseBill.setCreateBy(order.getCreateBy());
    expenseBill.setCreateTime(DateUtils.getNowDate());
    //新增费用单
    expenseBillMapper.insertExpenseBill(expenseBill);
    return expenseBill;
  }

  /**
   * 插入费用账单数据
   * @param order 诊疗单
   * @return
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public ExpenseBill insertExpenseBill(DiagnosisRefundOrder order) {
    ExpenseBill expenseBill = new ExpenseBill();
    //填充基本单据信息
    expenseBill.setBizId(order.getId());
    expenseBill.setBizNo(order.getOrderNo());
    expenseBill.setBizType(ExpenseBillBizTypeEnum.TREATMENT_RETURN_ORDER.getType());
    expenseBill.setStatus(ExpenseBillStatusEnum.TO_BE_CONFIRMED.getStatus());
    //填充业务数据信息
    expenseBill.setPatientId(order.getPatientId());
    //expenseBill.setReceivableCost(order.getTotalRefundAmount());
    //expenseBill.setPreferentialCost();
    expenseBill.setActCost(order.getTotalRefundAmount());
    //创建人信息
    expenseBill.setDeptId(order.getDeptId());
    expenseBill.setTenantId(order.getTenantId());
    expenseBill.setCreateBy(order.getCreateBy());
    expenseBill.setCreateTime(DateUtils.getNowDate());
    //新增费用单
    expenseBillMapper.insertExpenseBill(expenseBill);
    return expenseBill;
  }
  /**
   * 确认费用账单数据
   * @param dto
   * @return
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public int confirmExpenseBill(DiagnosisRefundOrderConfirmDto dto) {
    //更新费用账单
    ExpenseBill expenseBill = new ExpenseBill();
    expenseBill.setBizId(dto.getId());
    expenseBill.setBizType(ExpenseBillBizTypeEnum.TREATMENT_RETURN_ORDER.getType());
    expenseBill.setStatus(1);
    expenseBill.setRemark(dto.getVoucherRemark());
    iSysAccessoryService.insertStringUrlList(dto.getVoucherUrlList(),dto.getId().toString(),5,1);
    return expenseBillMapper.updateByParam(expenseBill);
  }
  /**
   * 删除费用账单数据
   * @param bizId 业务id
   * @param bizType 业务类型 ExpenseBillBizTypeEnum
   * @return
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public int delExpenseBill(Long bizId, Integer bizType) {
    ExpenseBill expenseBill = new ExpenseBill();
    expenseBill.setBizId(bizId);
    expenseBill.setBizType(bizType);
    return expenseBillMapper.deleteByParam(expenseBill);
  }
}
